#pragma once

#include "Requestor.hpp"

namespace xu
{
    namespace client
    {
        // 服务注册
        class Provider
        {
        public:
            using Ptr = std::shared_ptr<Provider>;

            Provider(const Requestor::Ptr &requestor) : _requestor(requestor)
            {}
            // 注册
            bool RegistryMethod(const BaseConnection::Ptr &conn, const std::string &method, const Address &host)
            {
                // 1.组织请求
                auto req_msg = MessageFactory::create<ServiceRequest>();
                req_msg->SetId(UUID::uuid());
                req_msg->SetMethod(method);
                req_msg->SetMType(MType::REQ_SERVICE);
                req_msg->SetHost(host);
                req_msg->SetOptype(ServiceOptype::SERVICE_REGISTRY);

                // 2.发送请求
                BaseMessage::Ptr msg;
                bool ret = _requestor->Send(conn, req_msg, msg);
                if (ret == false)
                {
                    LOG(LogLevel::ERROR) << "发送失败";
                    return false;
                }

                // 3.响应
                ServiceResponse::Ptr rsp_msg = std::dynamic_pointer_cast<ServiceResponse>(msg);
                if (rsp_msg.get() == nullptr)
                {
                    LOG(LogLevel::ERROR) << "向下转型失败";
                    return false;
                }

                if (rsp_msg->Rcode() != RCode::RCODE_OK)
                {
                    LOG(LogLevel::ERROR) << "注册失败 ： " << errReason(rsp_msg->Rcode());
                    return false;
                }

                LOG(LogLevel::INFO) << "注册成功";
                return true;
            }

        private:
            Requestor::Ptr _requestor;
        };


        




        class MethodHost
        {
        public:
            using ptr = std::shared_ptr<MethodHost>;
            MethodHost()
            {
            }
            MethodHost(const std::vector<std::pair<bool,Address>> &methodhost)
                : _methodhost(methodhost)
            {
            }

            void AddMethodHost(const Address &host)
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                _methodhost.push_back(std::make_pair(false,host));
            }

            void DelMethodHost(const Address &host)
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                auto it = _methodhost.begin();
                while (it != _methodhost.end())
                {
                    if (it->second == host)
                    {
                        _methodhost.erase(it);
                        LOG(LogLevel::DEBUG)<<"移除一个主机"<<it->second.second;
                        break;
                    }
                    ++it;
                }
            }

            Address GetMethodHost()
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                for(auto &e : _methodhost)
                {
                    if(e.first == false)
                    {
                        LOG(LogLevel::DEBUG)<<"获取ip:"<<e.second.first<<"  获取的port: "<< e.second.second;
                        return e.second;
                    }
                }
               

               if(!_methodhost.empty())
               {
                    int index = generateRandomInt(0,_methodhost.size()-1);
                    LOG(LogLevel::DEBUG)<<"不存在时：获取ip:"<<_methodhost[index].second.first<<"  获取的port: "<< _methodhost[index].second.second;
                    return _methodhost[index].second;
               }

               return Address();
            }

            void ReviseOverload(bool overload,const Address &host)
            {
                LOG(LogLevel::DEBUG)<<" ReviseOverload:"<<(int)overload;
                std::unique_lock<std::mutex> _lock(_mutex);
                for(auto &e : _methodhost)
                {
                    if(e.second == host)
                    {
                        e.first = overload;
                        LOG(LogLevel::DEBUG)<<"改变状态:"<<(int)overload;
                        break;
                    }
                }

                for(auto &e : _methodhost)
                {
                    LOG(LogLevel::DEBUG)<<"获取ip:"<<e.second.first<<"  获取的port: "<< e.second.second;
                    LOG(LogLevel::DEBUG)<<" overload :" <<e.first;
                }


            }

        private:
            std::mutex _mutex;
            std::vector<std::pair<bool,Address>> _methodhost;
            
        };

        class Discoverer
        {
        public:
            using OfflineCallback = std::function<void(const Address&)>;
            using Ptr = std::shared_ptr<Discoverer>;
            Discoverer(const Requestor::Ptr& requestor,const OfflineCallback & callback)
            :_requestor(requestor),
            _callback(callback)
            {}

            bool serviceDiscovery(const BaseConnection::Ptr &conn, const std::string &method, Address &host)
            {
                //1.当前发现过这个服务
                {
                    std::unique_lock<std::mutex> _lock(_mutex);
                    auto it = _method_host.find(method);
                    if(it != _method_host.end())
                    {
                        host = it->second->GetMethodHost();
                        if(host == Address())
                        {
                            return false;
                        }
                        return true;
                    }
                }

                //2.当前没有发现过该服务
                //2.1组织请求
                auto req_msg = MessageFactory::create<ServiceRequest>();
                req_msg->SetId(UUID::uuid());
                req_msg->SetMethod(method);
                req_msg->SetMType(MType::REQ_SERVICE);
                req_msg->SetOptype(ServiceOptype::SERVICE_DISCOVERY);

                // 2.2发送请求
                BaseMessage::Ptr msg;
                bool ret = _requestor->Send(conn, req_msg, msg);
                if (ret == false)
                {
                    LOG(LogLevel::ERROR) << "发送失败";
                    return false;
                }

                // 2.3处理响应
                ServiceResponse::Ptr rsp_msg = std::dynamic_pointer_cast<ServiceResponse>(msg);
                if (rsp_msg.get() == nullptr)
                {
                    LOG(LogLevel::ERROR) << "向下转型失败";
                    return false;
                }

                if (rsp_msg->Rcode() != RCode::RCODE_OK)
                {
                    LOG(LogLevel::ERROR) << "发现服务失败 : " << errReason(rsp_msg->Rcode());
                    return false;
                }

                std::unique_lock<std::mutex> _lock(_mutex);
                std::vector<std::pair<bool,Address>> res;
                for(const auto e : rsp_msg->Host())
                {
                    res.push_back(std::make_pair(false,e));
                }
                auto methodhost = std::make_shared<MethodHost>(res);
                _method_host[method] = methodhost;
                host = methodhost->GetMethodHost();
                if(host == Address())
                {
                    return false;
                }

                LOG(LogLevel::INFO)<<"服务发现完成";

                return true;

            }

            //作为回调函数注册到客户端里
            void onServiceRequest(const BaseConnection::Ptr &conn, const ServiceRequest::Ptr &msg)
            {
                auto optype = msg->Optype();
                auto method = msg->Method();
                //1.服务上线
                if(optype == ServiceOptype::SERVICE_ONLINE)
                {
                    std::unique_lock<std::mutex> _lock(_mutex);
                    //1.1以前注册过但是现在不在了
                    auto it = _method_host.find(method);
                    if(it == _method_host.end())
                    {
                        auto methodhost = std::make_shared<MethodHost>();
                        methodhost->AddMethodHost(msg->Host());
                        _method_host[method] = methodhost;
                    }
                    //1.2存在
                    else
                    {
                        it->second->AddMethodHost(msg->Host());
                    }

                    LOG(LogLevel::DEBUG)<<"服务上线了"<<msg->Host().first<<": "<<msg->Host().second;
                }
                //2.服务下线
                else if(optype == ServiceOptype::SERVICE_OFFLINE)
                {
                    std::unique_lock<std::mutex> _lock(_mutex);
                    auto it = _method_host.find(method);
                    if(it != _method_host.end())
                    {
                        it->second->DelMethodHost(msg->Host());
                        LOG(LogLevel::DEBUG)<<"服务下线了"<<msg->Host().first<<": "<<msg->Host().second;
                        _callback(msg->Host());
                    }
                   
                }
                //3.服务负载通知
                else if(optype == ServiceOptype::SERVICE_OVERLOAD)
                {
                    std::unique_lock<std::mutex> _lock(_mutex);
                    auto it = _method_host.find(method);
                    if(it != _method_host.end())
                    {
                        it->second->ReviseOverload(msg->Overload(),msg->Host());
                    }
                    LOG(LogLevel::DEBUG)<<"客户端收到负载";
                }

                
                LOG(LogLevel::INFO)<<"服务上下线完成";
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string,MethodHost::ptr> _method_host;
            Requestor::Ptr _requestor;
            OfflineCallback _callback;
        };
    }

}
